package com.maimao.kill.utils;

import com.maimao.core.constant.KillConstant;
import com.maimao.kill.rabbit.RabbitService;
import com.maimao.kill.service.KillGoodsService;
import com.maimao.kill.service.KillService;
import com.maimao.model.kill.KillGoods;
import com.maimao.model.kill.dto.KillDto;
import lombok.extern.slf4j.Slf4j;
import org.redisson.RedissonTopic;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Queue;
import java.util.concurrent.*;

/**
 * @author MaoLin Wang
 * @date 2021/4/13 11:58 下午
 */
@Component
@Slf4j
public class KillQueue {

    /**
     * 库存未初始化标识
     */
    public static final long UN_INIT_STOCK = -3L;

    @Autowired
    private KillService killService;

    @Autowired
    private KillGoodsService killGoodsService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

    private Queue<KillDto> queue = new ConcurrentLinkedDeque<>();

    private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(8, new ThreadPoolExecutor.CallerRunsPolicy());

    public void enQueue(KillDto killDto) {
        queue.offer(killDto);
    }

    public KillQueue() {
        doExecute();
    }

    private void doExecute() {
        executorService.scheduleWithFixedDelay(() -> {
            KillDto dto = queue.poll();
            if (null != dto) {
                reduceStock(dto.getKillId(), dto.getUserId());
            }
        }, 0, 1, TimeUnit.MILLISECONDS);
    }

    private void reduceStock(Long killId, Long userId) {
        String killStockKey = KillConstant.KILL_STOCK_KEY + killId;
        long stock = killService.reduceStock(killStockKey, 1, KillService.REDIS_STOCK_LUA);
        if (stock == UN_INIT_STOCK) {
            //未初始化
            RLock lock = redissonClient.getLock("kill_lock");
            try {
                lock.lock(2, TimeUnit.SECONDS);
                stock = killService.reduceStock(killStockKey, 1, KillService.REDIS_STOCK_LUA);
                if (stock == UN_INIT_STOCK) {
                    KillGoods details = killGoodsService.details(killId);
                    redisTemplate.opsForValue().set(killStockKey, details == null ? 0 : details.getStock());
                    stock = killService.reduceStock(killStockKey, 1, KillService.REDIS_STOCK_LUA);
                }
            } catch (Exception e) {
                log.error("init stock error :{}", killId);
            } finally {
                lock.unlock();
            }
        }
        if (stock >= 0) {
            //秒杀成功
           /* if (stock == 0) {
                KillService.stockMap.putIfAbsent(killId, false);
            }*/
            try {
                log.info("秒杀成功{}-{}", killId, userId);
                redisTemplate.opsForSet().add(KillConstant.KILL_GOODS_USER + killId, userId);
            rabbitService.sendKillSuccessMessage(new KillDto().setUserId(userId).setKillId(killId));
            } catch (Exception e) {
                log.error("kill fail {}-{} , ex:{}", killId, userId, e);
                killService.killFail(killId, userId);
            }

        } else {
           /* if (stock==-2){
                KillService.stockMap.put(killId, false);
            }*/
            log.error("秒杀失败{}-{}", killId, userId);

        }

    }
}
